#include <cstring>
#include <cassert>
#include "uvsettings.h"

namespace uv {
namespace settings {
    extern SettingsMap args;
    extern std::string help_string;
} }

void testBoolValue();
void testIntValue();
void testStringValue();
void testMain();
void testHelpMenu();
void cleanup();

int main() {
    testBoolValue();
    testIntValue();
    testStringValue();
    testMain();
    testHelpMenu();
    return 0;
}

void testBoolValue() {
    uv::settings::Value<bool> boolValue(false, "tag", "description");
    assert(!boolValue.getValue());
    assert(boolValue.toString().compare("tag\tdescription") == 0);
    boolValue.setOverride(true);
    assert(boolValue.getValue());
    boolValue.reset();
    assert(!boolValue.getValue());

    uv::settings::args["tag"] = "tru";
    assert(!boolValue.getValue());
    uv::settings::args["tag"] = "true";
    assert(boolValue.getValue());
    uv::settings::args["tag"] = "false";
    assert(boolValue.getValue());
    cleanup();
}

void testIntValue() {
    uv::settings::Value<int> intValue(0, "tag", "description");
    assert(intValue.getValue() == 0);
    
    uv::settings::args["tag"] = "true";
    assert(intValue.getValue() == 0);
    uv::settings::args["tag"] = "5";
    assert(intValue.getValue() == 5);
    cleanup();
}

void testStringValue() {
    uv::settings::Value<std::string> strValue("hello", "tag", "description");
    assert(strValue.getValue().compare("hello") == 0);

    uv::settings::args["tag"] = "world";
    assert(strValue.getValue().compare("world") == 0);
    cleanup();
}

void testMain() {
    int argc = 3;
    char *argv[3];
    argv[0] = new char[32];
    argv[1] = new char[32];
    argv[2] = new char[32];
    std::strcpy(argv[0], "--flag1");
    std::strcpy(argv[1], "true");
    std::strcpy(argv[2], "--flag2=false");

    uv::settings::main(argc, argv);
    uv::settings::SettingsMap::iterator end = uv::settings::args.end();
    assert(uv::settings::args.find("flag1") != end);
    assert(uv::settings::args.find("flag2") != end);
    assert(uv::settings::args["flag1"].compare("true") == 0);
    assert(uv::settings::args["flag2"].compare("false") == 0);

    delete argv[0];
    delete argv[1];
    delete argv[2];
    cleanup();
}

void testHelpMenu() {
    uv::settings::Value<bool> val1(true, "tag1", "description1");
    uv::settings::Value<bool> val2(false, "tag2", "description2");
    std::string expected_result = "tag1\tdescription1\ntag2\tdescription2\n";
    assert(uv::settings::getHelpString().compare(expected_result) == 0);
    cleanup();
}

void cleanup() {
    uv::settings::args.clear();
    uv::settings::help_string.clear();
}
